#define MYNAME "GARMIN"
static const char *portname;
static short_handle mkshort_handle;
+static GPS_PWay *tx_waylist;
static GPS_PWay *tx_routelist;
static GPS_PWay *cur_tx_routelist_entry;
static GPS_PTrack *tx_tracklist;
return "";
}
-static void
-waypoint_write(void)
+static int
+waypoint_prepare(void)
{
int i;
- int32 ret;
int n = waypt_count();
queue *elem, *tmp;
extern queue waypt_head;
- GPS_PWay *way;
int icon;
- way = xcalloc(n,sizeof(*way));
+ tx_waylist = xcalloc(n,sizeof(*tx_waylist));
for (i = 0; i < n; i++) {
- way[i] = sane_GPS_Way_New();
+ tx_waylist[i] = sane_GPS_Way_New();
}
i = 0;
* but rather a garmin "fixed length" buffer that's padded
* to the end with spaces. So this is NOT (strlen+1).
*/
- memcpy(way[i]->ident, ident, strlen(ident));
+ memcpy(tx_waylist[i]->ident, ident, strlen(ident));
if (global_opts.synthesize_shortnames) {
xfree(ident);
}
- way[i]->ident[sizeof(way[i]->ident)-1] = 0;
+ tx_waylist[i]->ident[sizeof(tx_waylist[i]->ident)-1] = 0;
// If we were explictly given a comment from GPX, use that.
// This logic really is horrible and needs to be untangled.
if (wpt->description &&
global_opts.smart_names && !wpt->gc_data->diff) {
- memcpy(way[i]->cmnt, wpt->description, strlen(wpt->description));
+ memcpy(tx_waylist[i]->cmnt, wpt->description, strlen(wpt->description));
} else {
if (global_opts.smart_names &&
wpt->gc_data->diff && wpt->gc_data->terr) {
get_gc_info(wpt),
wpt->gc_data->diff, wpt->gc_data->terr,
src);
- memcpy(way[i]->cmnt, obuf, strlen(obuf));
+ memcpy(tx_waylist[i]->cmnt, obuf, strlen(obuf));
} else {
- memcpy(way[i]->cmnt, src, strlen(src));
+ memcpy(tx_waylist[i]->cmnt, src, strlen(src));
}
}
- way[i]->lon = wpt->longitude;
- way[i]->lat = wpt->latitude;
+ tx_waylist[i]->lon = wpt->longitude;
+ tx_waylist[i]->lat = wpt->latitude;
if (deficon) {
icon = gt_find_icon_number_from_desc(deficon, PCX);
if (gps_waypt_type == 103) {
icon = d103_icon_number_from_symbol(wpt->icon_descr);
}
- way[i]->smbl = icon;
+ tx_waylist[i]->smbl = icon;
if (wpt->altitude == unknown_alt) {
- way[i]->alt_is_unknown = 1;
- way[i]->alt = 0;
+ tx_waylist[i]->alt_is_unknown = 1;
+ tx_waylist[i]->alt = 0;
} else {
- way[i]->alt = wpt->altitude;
+ tx_waylist[i]->alt = wpt->altitude;
}
if (wpt->creation_time) {
- way[i]->time = wpt->creation_time;
- way[i]->time_populated = 1;
+ tx_waylist[i]->time = wpt->creation_time;
+ tx_waylist[i]->time_populated = 1;
}
if (category) {
- way[i]->category = 1 << (atoi(category) - 1);
+ tx_waylist[i]->category = 1 << (atoi(category) - 1);
}
if (categorybits) {
- way[i]->category = categorybits;
+ tx_waylist[i]->category = categorybits;
}
#if SOON
- garmin_fs_garmin_before_write(wpt, way[i], gps_waypt_type);
+ garmin_fs_garmin_before_write(wpt, tx_waylist[i], gps_waypt_type);
#endif
i++;
}
- if ((ret = GPS_Command_Send_Waypoint(portname, way, n, waypt_write_cb)) < 0) {
+ return n;
+}
+
+static void
+waypoint_write(void)
+{
+ int i, n;
+ int32 ret;
+
+ n = waypoint_prepare();
+
+ if ((ret = GPS_Command_Send_Waypoint(portname, tx_waylist, n, waypt_write_cb)) < 0) {
fatal(MYNAME ":communication error sending wayoints..\n");
}
for (i = 0; i < n; ++i) {
- GPS_Way_Del(&way[i]);
+ GPS_Way_Del(&tx_waylist[i]);
}
if (global_opts.verbose_status) {
fprintf(stdout, "\r\n");
fflush(stdout);
}
- xfree(way);
+ xfree(tx_waylist);
}
static void
cur_tx_tracklist_entry++;
}
-static void
-track_write(void)
+static int
+track_prepare(void)
{
int i;
int n = track_waypt_count() + track_count();
my_track_count = 0;
track_disp_all(track_hdr_pr, route_noop, track_waypt_pr);
+ return n;
+}
+
+static void
+track_write(void)
+{
+ int i, n;
+
+ n = track_prepare();
+
GPS_Command_Send_Track(portname, tx_tracklist, n);
for (i = 0; i < n; i++) {
xfree(tx_tracklist);
}
+static void
+course_write(void)
+{
+ int i, n_trk, n_wpt;
+
+ n_wpt = waypoint_prepare();
+ n_trk = track_prepare();
+
+ GPS_Command_Send_Track_As_Course(portname, tx_tracklist, n_trk,
+ tx_waylist, n_wpt);
+
+ for (i = 0; i < n_wpt; ++i) {
+ GPS_Way_Del(&tx_waylist[i]);
+ }
+ xfree(tx_waylist);
+
+ for (i = 0; i < n_trk; i++) {
+ GPS_Track_Del(&tx_tracklist[i]);
+ }
+ xfree(tx_tracklist);
+}
+
static void
data_write(void)
{
return;
}
- if (global_opts.masked_objective & WPTDATAMASK)
- waypoint_write();
+ /* If we have both trackpoints and waypoints and the device
+ * supports courses, combine them to a course. Otherwise,
+ * send tracks & waypoints separately.
+ */
+ if ((global_opts.masked_objective & WPTDATAMASK) &&
+ (global_opts.masked_objective & TRKDATAMASK) &&
+ gps_course_transfer != -1)
+ {
+ course_write();
+ }
+ else
+ {
+ if (global_opts.masked_objective & WPTDATAMASK)
+ waypoint_write();
+ if (global_opts.masked_objective & TRKDATAMASK)
+ track_write();
+ }
if (global_opts.masked_objective & RTEDATAMASK)
route_write();
- if (global_opts.masked_objective & TRKDATAMASK)
- track_write();
}
static void GPS_D550_Send(UC *data, GPS_PAlmanac alm);
static void GPS_D551_Send(UC *data, GPS_PAlmanac alm);
-static UC Is_Trackpoint_Invalid(GPS_PTrack *trk);
+static UC Is_Trackpoint_Invalid(GPS_PTrack trk);
int32 gps_save_id;
/* @func GPS_A301_Get ******************************************************
**
-** Get track data from GPS
+** Get track data from GPS (A301/A302)
**
** @param [r] port [const char *] serial port
** @param [w] trk [GPS_PTrack **] track array
+** @param [r] protoid [int] protocol ID (301 or 302)
**
** @return [int32] number of track entries
************************************************************************/
-int32 GPS_A301_Get(const char *port, GPS_PTrack **trk, pcb_fn cb)
+int32 GPS_A301_Get(const char *port, GPS_PTrack **trk, pcb_fn cb, int protoid)
{
static UC data[2];
gpsdevh *fd;
GPS_PPacket rec;
int32 n;
int32 i;
+ US Pid_Trk_Data, Pid_Trk_Hdr, Cmnd_Transfer_Trk;
+ int32 trk_type, trk_hdr_type;
if(gps_trk_transfer == -1)
return GPS_UNSUPPORTED;
+ /* A301 and A302 are similar except for all these protocol IDs */
+ switch (protoid)
+ {
+ case 301:
+ Pid_Trk_Data = LINK_ID[gps_link_type].Pid_Trk_Data;
+ Pid_Trk_Hdr = LINK_ID[gps_link_type].Pid_Trk_Hdr;
+ Cmnd_Transfer_Trk = COMMAND_ID[gps_device_command].Cmnd_Transfer_Trk;
+ trk_type = gps_trk_type;
+ trk_hdr_type = gps_trk_hdr_type;
+ break;
+ case 302:
+ Pid_Trk_Data = LINK_ID[gps_link_type].Pid_Course_Trk_Data;
+ Pid_Trk_Hdr = LINK_ID[gps_link_type].Pid_Course_Trk_Hdr;
+ Cmnd_Transfer_Trk = COMMAND_ID[gps_device_command].Cmnd_Transfer_Course_Tracks;
+ trk_type = gps_run_crs_trk_type;
+ trk_hdr_type = gps_run_crs_trk_hdr_type;
+ break;
+ default:
+ GPS_Error("A301_Get: Bad protocol ID %d", protoid);
+ return GPS_UNSUPPORTED;
+ }
+
/* Only those GPS' with L001 can send track data */
- if(!LINK_ID[gps_link_type].Pid_Trk_Data)
+ if(!Pid_Trk_Data)
{
GPS_Warning("A301 protocol unsupported");
return GPS_UNSUPPORTED;
if(!GPS_Device_On(port, &fd))
return gps_errno;
- if ((gps_trk_type == pD304) && gps_run_transfer != -1) {
+ if ((trk_type == pD304) && gps_run_transfer != -1) {
drain_run_cmd(fd);
}
if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New()))
return MEMORY_ERROR;
- GPS_Util_Put_Short(data,
- COMMAND_ID[gps_device_command].Cmnd_Transfer_Trk);
+ GPS_Util_Put_Short(data, Cmnd_Transfer_Trk);
GPS_Make_Packet(&tra, LINK_ID[gps_link_type].Pid_Command_Data,
data,2);
if(!GPS_Write_Packet(fd,tra))
return gps_errno;
if(!GPS_Send_Ack(fd, &tra, &rec))
return gps_errno;
- if(rec->type == LINK_ID[gps_link_type].Pid_Trk_Hdr)
+ if(rec->type == Pid_Trk_Hdr)
{
- switch(gps_trk_hdr_type)
+ switch(trk_hdr_type)
{
case pD310:
case pD312:
continue;
}
- if(rec->type != LINK_ID[gps_link_type].Pid_Trk_Data)
+ if(rec->type != Pid_Trk_Data)
{
GPS_Error("A301_Get: Non-Pid_Trk_Data");
return FRAMING_ERROR;
(*trk)[i]->ishdr = 0;
- switch(gps_trk_type)
+ switch(trk_type)
{
case pD300:
GPS_D300b_Get(&((*trk)[i]),rec->data);
case pD303:
case pD304:
GPS_D303b_Get(&((*trk)[i]),rec->data);
+ /* Fitness devices don't send track segment markers, so we have
+ * to create them ourselves. We do so at the beginning of the
+ * track or if the device signals a pause by sending two
+ * invalid points in a row.
+ */
+ if (i>0)
+ {
+ if ((*trk)[i-1]->ishdr ||
+ (Is_Trackpoint_Invalid((*trk)[i-1]) &&
+ Is_Trackpoint_Invalid((*trk)[i])))
+ {
+ (*trk)[i]->tnew = 1;
+ }
+ }
break;
default:
GPS_Error("A301_GET: Unknown track protocol");
return PROTOCOL_ERROR;
}
/* Cheat and don't _really_ pass the trkpt back */
- cb(n, NULL);
+ if (cb)
+ cb(n, NULL);
}
if(!GPS_Packet_Read(fd, &rec))
}
-/* @func GPS_A302_Get ******************************************************
-**
-** Get course track data from GPS with protocol A302
-**
-** @param [r] port [const char *] serial port
-** @param [w] trk [GPS_PTrack **] track array
-**
-** @return [int32] number of track entries
-************************************************************************/
-/* FIXME: Merge with GPS_A301_Get()? */
-int32 GPS_A302_Get(const char *port, GPS_PTrack **trk, pcb_fn cb)
-{
- static UC data[2];
- gpsdevh *fd;
- GPS_PPacket tra;
- GPS_PPacket rec;
- int32 n;
- int32 i;
-
- if(gps_trk_transfer == -1)
- return GPS_UNSUPPORTED;
-
- /* Only those GPS' with L001 can send track data */
- if (!LINK_ID[gps_link_type].Pid_Course_Trk_Data)
- {
- GPS_Warning("Course track data unsupported");
- return GPS_UNSUPPORTED;
- }
-
- if(!GPS_Device_On(port, &fd))
- return gps_errno;
-
- if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New()))
- return MEMORY_ERROR;
-
- GPS_Util_Put_Short(data,
- COMMAND_ID[gps_device_command].Cmnd_Transfer_Course_Tracks);
- GPS_Make_Packet(&tra, LINK_ID[gps_link_type].Pid_Command_Data,
- data,2);
- if(!GPS_Write_Packet(fd,tra))
- return gps_errno;
- if(!GPS_Get_Ack(fd, &tra, &rec))
- return gps_errno;
- if(!GPS_Packet_Read(fd, &rec))
- return gps_errno;
- if(!GPS_Send_Ack(fd, &tra, &rec))
- return gps_errno;
-
-
- n = GPS_Util_Get_Short(rec->data);
-
- if(n)
- if(!((*trk)=(GPS_PTrack *)malloc(n*sizeof(GPS_PTrack))))
- {
- GPS_Error("A302b_Get: Insufficient memory");
- return MEMORY_ERROR;
- }
- for(i=0;i<n;++i)
- if(!((*trk)[i]=GPS_Track_New()))
- return MEMORY_ERROR;
-
- for(i=0;i<n;++i)
- {
- if(!GPS_Packet_Read(fd, &rec))
- return gps_errno;
- if(!GPS_Send_Ack(fd, &tra, &rec))
- return gps_errno;
- if (rec->type == LINK_ID[gps_link_type].Pid_Course_Trk_Hdr)
- {
- switch(gps_run_crs_trk_hdr_type)
- {
- case pD310:
- case pD312:
- GPS_D310_Get(&((*trk)[i]),rec->data);
- break;
- case pD311:
- GPS_D311_Get(&((*trk)[i]),rec->data);
- break;
- default:
- GPS_Error("A302b_Get: Unknown track header data");
- return PROTOCOL_ERROR;
- }
- (*trk)[i]->ishdr = 1;
- continue;
- }
-
- if (rec->type != LINK_ID[gps_link_type].Pid_Course_Trk_Data)
- {
- GPS_Error("A302b_Get: Non-Pid_Course_Trk_Data");
- return FRAMING_ERROR;
- }
-
- (*trk)[i]->ishdr = 0;
-
- switch(gps_run_crs_trk_type)
- {
- case pD300:
- GPS_D300b_Get(&((*trk)[i]),rec->data);
- break;
- case pD301:
- GPS_D301b_Get(&((*trk)[i]),rec->data);
- break;
- case pD302:
- GPS_D302b_Get(&((*trk)[i]),rec->data);
- break;
- case pD303:
- case pD304:
- GPS_D303b_Get(&((*trk)[i]),rec->data);
- /* Fitness devices don't send track segment markers, so we have
- * to create them ourselves. We do so at the beginning of the
- * track or if the device signals a pause by sending two
- * invalid points in a row.
- */
- if (i>0)
- {
- if ((*trk)[i-1]->ishdr ||
- (Is_Trackpoint_Invalid(&((*trk)[i-1])) &&
- Is_Trackpoint_Invalid(&((*trk)[i]))))
- {
- (*trk)[i]->tnew = 1;
- }
- }
- break;
- default:
- GPS_Error("A301_GET: Unknown track protocol");
- return PROTOCOL_ERROR;
- }
- /* Cheat and don't _really_ pass the trkpt back */
- if (cb) {
- cb(n, NULL);
- }
- }
-
- if(!GPS_Packet_Read(fd, &rec))
- return gps_errno;
- if(!GPS_Send_Ack(fd, &tra, &rec))
- return gps_errno;
- if(rec->type != LINK_ID[gps_link_type].Pid_Xfer_Cmplt)
- {
- GPS_Error("A302b_Get: Error transferring course tracks");
- return FRAMING_ERROR;
- }
-
- if(i != n)
- {
- GPS_Error("A302b_Get: Course track entry number mismatch");
- return FRAMING_ERROR;
- }
-
- GPS_Packet_Del(&tra);
- GPS_Packet_Del(&rec);
-
- if(!GPS_Device_Off(fd))
- return gps_errno;
-
- return n;
-}
-
-
/* @func GPS_A300_Send **************************************************
**
** Send track log to GPS
/* @func GPS_A301_Send **************************************************
**
-** Send track log to GPS
+** Send track log to GPS (A301/A302). Note that in case of A302, track
+** log transfer is part of the course transfer sequence, so we must not
+** call GPS_Device_On/Off() but expect to get a usable gpsdevh from our
+** caller.
**
** @param [r] port [const char *] serial port
** @param [r] trk [GPS_PTrack *] track array
** @param [r] n [int32] number of track entries
+** @param [r] protoid [int] protocol ID (301 or 302)
+** @param [r] fd [gpsdevh *] pointer to communication port (for A302 only)
**
** @return [int32] success
************************************************************************/
-int32 GPS_A301_Send(const char *port, GPS_PTrack *trk, int32 n)
+int32 GPS_A301_Send(const char *port, GPS_PTrack *trk, int32 n, int protoid,
+ gpsdevh *fd)
{
UC data[GPS_ARB_LEN];
- gpsdevh *fd;
GPS_PPacket tra;
GPS_PPacket rec;
- int32 i;
+ int32 i, j;
int32 len;
US method;
+ US Pid_Trk_Data, Pid_Trk_Hdr, Cmnd_Transfer_Trk;
+ int32 trk_type, trk_hdr_type;
if(gps_trk_transfer == -1)
return GPS_UNSUPPORTED;
+ /* A301 and A302 are similar except for all these protocol IDs */
+ switch (protoid)
+ {
+ case 301:
+ Pid_Trk_Data = LINK_ID[gps_link_type].Pid_Trk_Data;
+ Pid_Trk_Hdr = LINK_ID[gps_link_type].Pid_Trk_Hdr;
+ Cmnd_Transfer_Trk = COMMAND_ID[gps_device_command].Cmnd_Transfer_Trk;
+ trk_type = gps_trk_type;
+ trk_hdr_type = gps_trk_hdr_type;
+ break;
+ case 302:
+ Pid_Trk_Data = LINK_ID[gps_link_type].Pid_Course_Trk_Data;
+ Pid_Trk_Hdr = LINK_ID[gps_link_type].Pid_Course_Trk_Hdr;
+ Cmnd_Transfer_Trk = COMMAND_ID[gps_device_command].Cmnd_Transfer_Course_Tracks;
+ trk_type = gps_run_crs_trk_type;
+ trk_hdr_type = gps_run_crs_trk_hdr_type;
+ break;
+ default:
+ GPS_Error("A301_Send: Bad protocol ID %d", protoid);
+ return GPS_UNSUPPORTED;
+ }
+
/* Only those GPS' with L001 can send track data */
- if(!LINK_ID[gps_link_type].Pid_Trk_Data)
+ if(!Pid_Trk_Data)
{
GPS_Warning("A301 protocol unsupported");
return GPS_UNSUPPORTED;
}
- if(!GPS_Device_On(port, &fd))
+ /* D303/304 marks track segments with two consecutive invalid track
+ * points. Create them unless we're at the beginning of a track or there
+ * are already invalid track points (because the track was downloaded
+ * using D303/304). This needs to be done here because it will change
+ * the number of track points.
+ */
+ if (trk_type == pD303 || trk_type == pD304)
+ {
+ for(i=0;i<n;++i)
+ {
+ if (trk[i]->tnew && i>0 && !trk[i]->ishdr && !trk[i-1]->ishdr)
+ {
+ /* Create in reverse order to avoid having to readjust the
+ * index after inserting the first point.
+ */
+ for (j=i; j>=i-1; j--)
+ {
+ if (!Is_Trackpoint_Invalid(trk[j]))
+ {
+ GPS_PTrack trkpt = GPS_Track_New();
+ *trkpt = *(trk[j]);
+ trkpt->no_latlon = 1;
+ trkpt->alt = 1e25;
+ trkpt->distance = 1e25;
+ trkpt->heartrate = 0;
+ trkpt->cadence = 0xff;
+ trk = xrealloc(trk, (n+1) * sizeof(GPS_PTrack));
+ memmove(&trk[i+1], &trk[i], (n-i) * sizeof(GPS_PTrack));
+ n++;
+ trk[i] = trkpt;
+ }
+ }
+ }
+ }
+ }
+
+ if(protoid != 302 && !GPS_Device_On(port, &fd))
return gps_errno;
if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New()))
{
if(trk[i]->ishdr)
{
- method = LINK_ID[gps_link_type].Pid_Trk_Hdr;
+ method = Pid_Trk_Hdr;
- switch(gps_trk_hdr_type)
+ switch(trk_hdr_type)
{
case pD310:
case pD312:
GPS_D311_Send(data,trk[i],&len);
break;
default:
- GPS_Error("A301_Send: Unknown track protocol %d", gps_trk_hdr_type);
+ GPS_Error("A301_Send: Unknown track protocol %d", trk_hdr_type);
return PROTOCOL_ERROR;
}
}
else
{
- method = LINK_ID[gps_link_type].Pid_Trk_Data;
+ method = Pid_Trk_Data;
- switch(gps_trk_type)
+ switch(trk_type)
{
case pD300:
GPS_D300_Send(data,trk[i],&len);
case pD302:
GPS_D301_Send(data,trk[i],&len,302);
break;
- case pD303:
- GPS_D303_Send(data,trk[i],&len,303);
- break;
+ case pD303:
case pD304:
- GPS_D303_Send(data,trk[i],&len,304);
+ GPS_D303_Send(data,trk[i],&len,(trk_type==pD303) ? 303 : 304);
break;
default:
GPS_Error("A301_Send: Unknown track protocol");
return PROTOCOL_ERROR;
}
}
-
GPS_Make_Packet(&tra, method, data, len);
return FRAMING_ERROR;
}
}
-
- GPS_Util_Put_Short(data,COMMAND_ID[gps_device_command].Cmnd_Transfer_Trk);
+ GPS_Util_Put_Short(data, Cmnd_Transfer_Trk);
GPS_Make_Packet(&tra, LINK_ID[gps_link_type].Pid_Xfer_Cmplt,
data,2);
if(!GPS_Write_Packet(fd,tra))
GPS_Packet_Del(&tra);
GPS_Packet_Del(&rec);
- if(!GPS_Device_Off(fd))
+ if(protoid != 302 && !GPS_Device_Off(fd))
return gps_errno;
return 1;
}
-/* @func GPS_A302_Send **************************************************
-**
-** Send Course-track log to GPS
-**
-** Note that different to other GPS_Axxx_Send functions, the device
-** communication is not initialized/ended within the function, since
-** this packet transfer is only part of a series of transfers to the
-** device. Communication init/end has to be handled by the caller.
-**
-** @param [r] port [const char *] serial port
-** @param [r] trk [GPS_PTrack *] track array
-** @param [r] n [int32] number of track entries
-** @param [r] fd [gpsdevh *] pointer to the communication port
-**
-** @return [int32] success
-************************************************************************/
-/* FIXME: Merge with GPS_A301_Send()? */
-int32 GPS_A302_Send(const char *port,
- GPS_PTrack *trk,
- int32 n,
- gpsdevh *fd)
-{
- UC data[GPS_ARB_LEN];
- GPS_PPacket tra;
- GPS_PPacket rec;
- int32 i;
- int32 len;
- US method;
-
- if(gps_trk_transfer == -1)
- return GPS_UNSUPPORTED;
-
- /* Only those GPS' with L001 can send track data */
- if(!LINK_ID[gps_link_type].Pid_Course_Trk_Data)
- {
- GPS_Warning("A302b: course-track protocol unsupported");
- return GPS_UNSUPPORTED;
- }
-
- if(!(tra = GPS_Packet_New()) || !(rec = GPS_Packet_New()))
- return MEMORY_ERROR;
-
- GPS_Util_Put_Short(data,(US) n);
- GPS_Make_Packet(&tra, LINK_ID[gps_link_type].Pid_Records,
- data,2);
- if(!GPS_Write_Packet(fd,tra))
- return gps_errno;
- if(!GPS_Get_Ack(fd, &tra, &rec))
- {
- GPS_Error("A302_Send: Course-track start data not acknowledged");
- return FRAMING_ERROR;
- }
-
- for(i=0;i<n;++i)
- {
- if(trk[i]->ishdr)
- {
- method = LINK_ID[gps_link_type].Pid_Course_Trk_Hdr;
-
- switch(gps_run_crs_trk_hdr_type)
- {
- case pD310:
- case pD312:
- GPS_D310_Send(data,trk[i],&len);
- break;
- case pD311:
- GPS_D311_Send(data,trk[i],&len);
- break;
- default:
- GPS_Error("A302_Send: Unknown track header type");
- return PROTOCOL_ERROR;
- }
- }
- else
- {
- method = LINK_ID[gps_link_type].Pid_Course_Trk_Data;
-
- switch(gps_run_crs_trk_type)
- {
- case pD300:
- GPS_D300_Send(data,trk[i],&len);
- break;
- case pD301:
- GPS_D301_Send(data,trk[i],&len, 301);
- break;
- case pD302:
- GPS_D301_Send(data,trk[i],&len, 302);
- break;
- case pD303:
- GPS_D303_Send(data,trk[i],&len,303);
- break;
- case pD304:
- GPS_D303_Send(data,trk[i],&len,304);
- break;
- default:
- GPS_Error("A302_Send: Unknown track protocol");
- return PROTOCOL_ERROR;
- }
- }
-
- GPS_Make_Packet(&tra, method, data,(US) len);
-
- if(!GPS_Write_Packet(fd,tra))
- return gps_errno;
-
- if(!GPS_Get_Ack(fd, &tra, &rec))
- {
- GPS_Error("A302_Send: Course-track packet not acknowledged");
- return FRAMING_ERROR;
- }
- }
-
- GPS_Util_Put_Short(data,COMMAND_ID[gps_device_command].Cmnd_Transfer_Course_Tracks);
- GPS_Make_Packet(&tra, LINK_ID[gps_link_type].Pid_Xfer_Cmplt,
- data,2);
- if(!GPS_Write_Packet(fd,tra))
- return gps_errno;
- if(!GPS_Get_Ack(fd, &tra, &rec))
- {
- GPS_Error("A302_Send: Course-track complete data not acknowledged");
- return FRAMING_ERROR;
- }
-
- GPS_Packet_Del(&tra);
- GPS_Packet_Del(&rec);
-
- return 1;
-}
-
-
/* @func GPS_D300_Get ******************************************************
**
** Get track data
p+=sizeof(float);
if (protoid == 304) {
- GPS_Util_Put_Float(p, 1.0e25f);
+ GPS_Util_Put_Float(p, 1.0e25f); /* Distance, not supported for now */
p+=sizeof(float);
}
p+=sizeof(char);
if (protoid == 304) {
- *p = trk->cadence;
+ *p = trk->cadence > 0 ? trk->cadence : 0xff;
p+=sizeof(char);
- *p = trk->cadence > 0 ? trk->cadence : 0xff;
+ *p = 0; /* Wheel sensor present, not supported for now */
p+=sizeof(char);
}
p=s;
- GPS_Util_Put_Int(p,GPS_Math_Deg_To_Semi(trk->lat));
+ /* Note: lat/lon == 0x7fffffff is only valid for D303/D304, but our
+ * caller shouldn't set no_latlon unless one of these protocols actually
+ * is in use */
+ GPS_Util_Put_Int(p,trk->no_latlon ? 0x7fffffff : GPS_Math_Deg_To_Semi(trk->lat));
p+=sizeof(int32);
- GPS_Util_Put_Int(p,GPS_Math_Deg_To_Semi(trk->lon));
+ GPS_Util_Put_Int(p,trk->no_latlon ? 0x7fffffff : GPS_Math_Deg_To_Semi(trk->lon));
p+=sizeof(int32);
GPS_Util_Put_Uint(p,GPS_Math_Utime_To_Gtime(trk->Time));
**
** @return [UC] 1 if the trackpoint is invalid
************************************************************************/
-static UC Is_Trackpoint_Invalid(GPS_PTrack *trk)
+static UC Is_Trackpoint_Invalid(GPS_PTrack trk)
{
/* FIXME: We should have more *_is_unknown fields instead of
* checking for special values here (e.g. cadence = 0 would be
* perfectly valid, but GPS_D303b_Get() chose to use it to mark
* nonexistent cadence data.
*/
- return (*trk)->no_latlon && (*trk)->distance > 1e24 &&
- !(*trk)->heartrate && !(*trk)->cadence;
+ return trk->no_latlon && trk->distance > 1e24 &&
+ !trk->heartrate && !trk->cadence;
}
int32 GPS_A201_Send(const char *port, GPS_PWay *way, int32 n);
int32 GPS_A300_Get(const char *port, GPS_PTrack **trk, pcb_fn cb);
-int32 GPS_A301_Get(const char *port, GPS_PTrack **trk, pcb_fn cb);
-int32 GPS_A302_Get(const char *port, GPS_PTrack **trk, pcb_fn cb);
+int32 GPS_A301_Get(const char *port, GPS_PTrack **trk, pcb_fn cb, int protoid);
int32 GPS_A300_Send(const char *port, GPS_PTrack *trk, int32 n);
-int32 GPS_A301_Send(const char *port, GPS_PTrack *trk, int32 n);
-int32 GPS_A302_Send(const char *port, GPS_PTrack *trk, int32 n,
+int32 GPS_A301_Send(const char *port, GPS_PTrack *trk, int32 n, int protoid,
gpsdevh *fd);
int32 GPS_D300_Get(GPS_PTrack *trk, int32 entries, gpsdevh *h);
********************************************************************/
#include "gps.h"
#include <stdio.h>
+#include <float.h>
/* @func GPS_Command_Off ***********************************************
break;
case pA301:
case pA302:
- ret = GPS_A301_Get(port,trk,cb);
+ ret = GPS_A301_Get(port,trk,cb,301);
break;
default:
GPS_Error("Get_Track: Unknown track protocol %d\n", gps_trk_transfer);
ret = GPS_A300_Send(port, trk, n);
break;
case pA301:
- ret = GPS_A301_Send(port, trk, n);
+ ret = GPS_A301_Send(port, trk, n, 301, NULL);
break;
case pA302:
/* Units with A302 don't support track upload, so we convert the
* track to a course on the fly and send that instead
*/
- ret = GPS_Command_Send_Track_As_Course(port, trk, n);
+ ret = GPS_Command_Send_Track_As_Course(port, trk, n, NULL, 0);
break;
default:
GPS_Error("Send_Track: Unknown track protocol %d.", gps_trk_transfer);
gps_trk_transfer);
break;
case pA302:
- *n_trk = GPS_A302_Get(port,trk,cb);
+ *n_trk = GPS_A301_Get(port,trk,cb,302);
break;
default:
GPS_Error("Get_Course: Unknown course track protocol %d\n",
** includes sending all course laps, course tracks and course points
** to the device.
**
-** Data integrity is being checked: only those course laps, tracks and
-** points are sent to the device which belong to a course in the course
-** array. Otherwise, those data will be silently dropped.
-**
** @param [r] port [const char *] serial port
** @param [w] crs [GPS_PCourse **] course array
** @param [w] clp [GPS_PCourse_Lap *] course lap array
gps_trk_transfer);
break;
case pA302:
- ret_trk = GPS_A302_Send(port,trk,n_trk,fd);
+ ret_trk = GPS_A301_Send(port,trk,n_trk,302,fd);
break;
default:
GPS_Error("Send_Course: Unknown course track protocol %d\n",
}
+/* @funcstatic Unique_Course_Index *************************************
+**
+** Choose a course index that's not yet used by another course.
+**
+** @param [r] crs [GPS_PCourse **] course array
+** @param [r] n_crs [int32] number of course entries
+**
+** @return [uint32] course index
+************************************************************************/
static uint32 Unique_Course_Index(GPS_PCourse *crs, int n_crs)
{
uint32 idx;
for (idx=0; ; idx++)
{
- for (i=0; i<n_crs; i++)
- if (crs[i]->index==idx)
- break; /* Already have this index */
- if (i>=n_crs)
- return idx; /* Found unused index */
+ for (i=0; i<n_crs; i++)
+ if (crs[i]->index==idx)
+ break; /* Already have this index */
+ if (i>=n_crs)
+ return idx; /* Found unused index */
}
}
+/* @funcstatic Unique_Track_Index ***************************************
+**
+** Choose a track index that's not yet used by another track referenced
+** by the courses.
+**
+** @param [r] crs [GPS_PCourse **] course array
+** @param [r] n_crs [int32] number of course entries
+**
+** @return [uint32] track index
+************************************************************************/
static uint32 Unique_Track_Index(GPS_PCourse *crs, int n_crs)
{
uint32 idx;
for (idx=0; ; idx++)
{
- for (i=0; i<n_crs; i++)
- if (crs[i]->track_index==idx)
- break; /* Already have this index */
- if (i>=n_crs)
- return idx; /* Found unused index */
+ for (i=0; i<n_crs; i++)
+ if (crs[i]->track_index==idx)
+ break; /* Already have this index */
+ if (i>=n_crs)
+ return idx; /* Found unused index */
}
}
+/* @funcstatic Calculate_Course_Lap_Data *******************************
+**
+** Calculate lap data totals from individual track points. Also
+** generates time stamps for track points if they don't have
+** time stamps yet (using an arbitrary speed of 10 km/h which is
+** currently hardcoded. This is required so that couse points can
+** refer to track points and identify them uniquely.
+**
+** @param [w] clp [GPS_PCourse_Lap] course lap to be calculated
+** @param [r] ctk [GPS_PTrack *] track array to calculate lap from
+** @param [r] ctk_start [int] start index of lap in track array
+** @param [r] ctk_end [int] end index of lap in track array
+**
+** @return [void]
+************************************************************************/
+static void
+Calculate_Course_Lap_Data(GPS_PCourse_Lap clp, GPS_PTrack *ctk,
+ int ctk_start, int ctk_end)
+{
+ int i;
+ double heartrate_sum = 0, cadence_sum = 0;
+ int heartrate_sum_time = 0, cadence_sum_time = 0;
+ double time_synth_speed = 10.0 * 1000 / 3600; /* speed in m/s */
+
+ if (ctk_start && ctk_end && !ctk[ctk_start]->Time)
+ ctk[ctk_start]->Time = GPS_Time_Now();
+ else
+ time_synth_speed = 0;
+
+ clp->total_dist = 0;
+ clp->avg_heart_rate = 0;
+ clp->max_heart_rate = 0;
+ clp->intensity = 0;
+ clp->avg_cadence = 0xff;
+ for (i=ctk_start; i <= ctk_end; i++)
+ {
+ if (ctk[i]->heartrate && ctk[i]->heartrate > clp->max_heart_rate)
+ clp->max_heart_rate = ctk[i]->heartrate;
+ if (i < ctk_end)
+ {
+ double dist = 0;
+ int seg_time;
+
+ if (!ctk[i]->no_latlon && !ctk[i+1]->no_latlon)
+ dist = gcgeodist(ctk[i]->lat, ctk[i]->lon,
+ ctk[i+1]->lat, ctk[i+1]->lon);
+ clp->total_dist += dist;
+
+ if (time_synth_speed)
+ ctk[i+1]->Time = ctk[i]->Time + (dist / time_synth_speed + 0.5);
+
+ seg_time = ctk[i+1]->Time - ctk[i]->Time;
+
+ if (ctk[i]->heartrate)
+ {
+ heartrate_sum += ctk[i]->heartrate * seg_time;
+ heartrate_sum_time += seg_time;
+ }
+ if (ctk[i]->cadence)
+ {
+ cadence_sum += ctk[i]->cadence * seg_time;
+ cadence_sum_time += seg_time;
+ }
+ }
+ }
+
+ clp->total_time = 0;
+ clp->begin_lat = 0x7fffffff;
+ clp->begin_lon = 0x7fffffff;
+ clp->end_lat = 0x7fffffff;
+ clp->end_lon = 0x7fffffff;
+ if (ctk_start && ctk_end)
+ {
+ clp->total_time = (ctk[ctk_end]->Time - ctk[ctk_start]->Time) * 100;
+ if (!ctk[ctk_start]->no_latlon && !ctk[ctk_end]->no_latlon)
+ {
+ clp->begin_lat = ctk[ctk_start]->lat;
+ clp->begin_lon = ctk[ctk_start]->lon;
+ clp->end_lat = ctk[ctk_end]->lat;
+ clp->end_lon = ctk[ctk_end]->lon;
+ }
+ }
+ if (heartrate_sum_time)
+ clp->avg_heart_rate = heartrate_sum / heartrate_sum_time;
+ if (cadence_sum_time)
+ clp->avg_cadence = cadence_sum / cadence_sum_time;
+}
+
+
+/* @funcstatic Course_Garbage_Collect **********************************
+**
+** Remove duplicate courses, then remove unreferenced laps, tracks and
+** course points from arrays.
+**
+** @param [w] crs [GPS_PCourse *] course array
+** @param [w] n_crs [int *] number of course entries
+** @param [w] clp [GPS_PCourse_Lap *] course lap array
+** @param [w] n_clp [int *] number of lap entries
+** @param [w] ctk [GPS_PTrack *] track array
+** @param [w] n_ctk [int *] number of track entries
+** @param [w] cpt [GPS_PCourse_Point *] course point array
+** @param [w] n_cpt [int *] number of course point entries
+**
+** @return [void]
+************************************************************************/
static void
Course_Garbage_Collect(GPS_PCourse *crs, int *n_crs,
GPS_PCourse_Lap *clp, int *n_clp,
GPS_PTrack *ctk, int *n_ctk,
- GPS_PCourse_Point *cpt, int *n_cpt) {
+ GPS_PCourse_Point *cpt, int *n_cpt)
+{
int i, j;
- /* Remove courses with duplicate names, keeping newest */
+ /* Remove courses with duplicate names, keeping newest.
+ * This is actually pretty important: Sending two courses with the same
+ * name to the device will result in internal data corruption on the
+ * device (e.g. "inventing" laps with weird course IDs that nobody ever
+ * transferred to it, that change with every upload of unrelated data
+ * and that can't be deleted except with a master reset by holding the
+ * Mode button during power on).
+ */
restart_courses:
for (i=*n_crs-1; i>0; i--)
{
- for (j=i-1; j>=0; j--)
- {
- if (!strcmp(crs[i]->course_name, crs[j]->course_name))
- {
- /* Remove course */
- GPS_Course_Del(&crs[j]);
- memmove(&crs[j], &crs[j+1], (*n_crs-j-1)*sizeof(*crs));
- (*n_crs)--;
- goto restart_courses;
- }
- }
+ for (j=i-1; j>=0; j--)
+ {
+ if (!strcmp(crs[i]->course_name, crs[j]->course_name))
+ {
+ /* Remove course */
+ GPS_Course_Del(&crs[j]);
+ memmove(&crs[j], &crs[j+1], (*n_crs-j-1)*sizeof(*crs));
+ (*n_crs)--;
+ goto restart_courses;
+ }
+ }
}
/* Remove unreferenced laps */
restart_laps:
- for (i=0; i<*n_clp; i++)
- {
- for (j=0; j<*n_crs; j++)
- if (crs[j]->index == clp[i]->course_index)
- break;
- if (j>=*n_crs)
+ for (i=0; i<*n_clp; i++)
{
- /* Remove lap */
- GPS_Course_Lap_Del(&clp[i]);
- memmove(&clp[i], &clp[i+1], (*n_clp-i-1)*sizeof(*clp));
- (*n_clp)--;
- goto restart_laps;
+ for (j=0; j<*n_crs; j++)
+ if (crs[j]->index == clp[i]->course_index)
+ break;
+ if (j>=*n_crs)
+ {
+ /* Remove lap */
+ GPS_Course_Lap_Del(&clp[i]);
+ memmove(&clp[i], &clp[i+1], (*n_clp-i-1)*sizeof(*clp));
+ (*n_clp)--;
+ goto restart_laps;
+ }
}
- }
- /* Remove unreferenced tracks */
+ /* Remove unreferenced tracks */
restart_tracks:
- for (i=0; i<*n_ctk; i++)
- {
- uint32 trk_idx;
-
- if (!ctk[i]->ishdr)
- continue;
- trk_idx = strtoul(ctk[i]->trk_ident, NULL, 0);
- for (j=0; j<*n_crs; j++)
- if (crs[j]->index == trk_idx)
- break;
- if (j>=*n_crs)
+ for (i=0; i<*n_ctk; i++)
{
- /* Remove track */
- for (j=i; j<*n_ctk; j++)
- {
- if (j!=i && ctk[j]->ishdr)
- break;
- GPS_Track_Del(&ctk[j]);
- }
- memmove(&ctk[i], &ctk[j], (*n_ctk-j)*sizeof(*ctk));
- *(n_ctk) -= j-i;
- goto restart_tracks;
+ uint32 trk_idx;
+
+ if (!ctk[i]->ishdr)
+ continue;
+ trk_idx = strtoul(ctk[i]->trk_ident, NULL, 0);
+ for (j=0; j<*n_crs; j++)
+ if (crs[j]->track_index == trk_idx)
+ break;
+ if (j>=*n_crs)
+ {
+ /* Remove track */
+ for (j=i; j<*n_ctk; j++)
+ {
+ if (j!=i && ctk[j]->ishdr)
+ break;
+ GPS_Track_Del(&ctk[j]);
+ }
+ memmove(&ctk[i], &ctk[j], (*n_ctk-j)*sizeof(*ctk));
+ *(n_ctk) -= j-i;
+ goto restart_tracks;
+ }
}
- }
- /* Remove unreferenced course points */
+ /* Remove unreferenced/duplicate course points */
restart_course_points:
- for (i=0; i<*n_cpt; i++)
- {
- for (j=0; j<*n_crs; j++)
- if (crs[j]->index == cpt[i]->course_index)
- break;
- if (j>=*n_crs)
+ for (i=0; i<*n_cpt; i++)
{
- /* Remove course point */
- GPS_Course_Point_Del(&cpt[i]);
- memmove(&cpt[i], &cpt[i+1], (*n_cpt-i-1)*sizeof(*cpt));
- (*n_cpt)--;
- goto restart_course_points;
+ /* Check for unreferenced point */
+ for (j=0; j<*n_crs; j++)
+ if (crs[j]->index == cpt[i]->course_index)
+ break;
+ if (j<*n_crs)
+ {
+ /* Check for duplicate point */
+ for (j=0; j<i; j++)
+ if (cpt[i]->course_index == cpt[j]->course_index &&
+ cpt[i]->track_point_time == cpt[j]->track_point_time)
+ break;
+ if (j>=i)
+ continue; /* Referenced & unique */
+ }
+ /* Remove course point */
+ GPS_Course_Point_Del(&cpt[i]);
+ memmove(&cpt[i], &cpt[i+1], (*n_cpt-i-1)*sizeof(*cpt));
+ (*n_cpt)--;
+ goto restart_course_points;
}
- }
}
**
** @param [r] port [const char *] serial port
** @param [r] trk [GPS_PTrack *] track array
-** @param [r] n [int32] number of track entries
+** @param [r] n_trk [int32] number of track entries
+** @param [r] wpt [GPS_PWay *] waypoint array
+** @param [r] n_wpt [int32] number of waypoint entries
**
** @return [int32] success
************************************************************************/
-int32 GPS_Command_Send_Track_As_Course(const char *port, GPS_PTrack *trk, int32 n)
+int32 GPS_Command_Send_Track_As_Course(const char *port, GPS_PTrack *trk, int32 n_trk,
+ GPS_PWay *wpt, int32 n_wpt)
{
GPS_PCourse *crs = NULL;
GPS_PCourse_Lap *clp = NULL;
GPS_PTrack *ctk = NULL;
GPS_PCourse_Point *cpt = NULL;
int n_crs, n_clp=0, n_ctk=0, n_cpt=0;
- int i, trk_end, trk_crs;
+ int i, j, trk_end, new_crs, first_new_ctk;
int32 ret;
/* Read existing courses from device */
if (n_crs < 0) return n_crs;
/* Create new course+lap+track points for each track */
- trk_crs = n_crs;
- for (i=0;i<n;i++) {
- if (!trk[i]->ishdr)
- continue;
-
- /* Find end of track */
- for (trk_end=i; trk_end<n-1; trk_end++)
- if (trk[trk_end+1]->ishdr)
- break;
- if (trk_end==i)
- trk_end=0; /* Empty track */
-
- /* Create & append course */
- crs = realloc(crs, (n_crs+1) * sizeof(GPS_PCourse));
- if (!crs) return MEMORY_ERROR;
- crs[n_crs] = GPS_Course_New();
- if (!crs[n_crs]) return MEMORY_ERROR;
-
- crs[n_crs]->index = Unique_Course_Index(crs, n_crs);
- strncpy(crs[n_crs]->course_name, trk[i]->trk_ident,
- sizeof(crs[n_crs]->course_name)-1);
-
- crs[n_crs]->track_index = Unique_Track_Index(crs, n_crs);
-
- /* Create & append new lap */
- clp = realloc(clp, (n_clp+1) * sizeof(GPS_PCourse_Lap));
- if (!clp) return MEMORY_ERROR;
- clp[n_clp] = GPS_Course_Lap_New();
- if (!clp[n_clp]) return MEMORY_ERROR;
-
- clp[n_clp]->course_index = crs[n_crs]->index; /* Index of associated course */
- clp[n_clp]->lap_index = 0; /* Lap index, unique per course */
- clp[n_clp]->total_time = 0; /* FIXME: Calculate */
- clp[n_clp]->total_dist = 0; /* FIXME: Calculate */
- if (trk_end)
- {
- clp[n_clp]->begin_lat = trk[i+1]->lat;
- clp[n_clp]->begin_lon = trk[i+1]->lon;
- clp[n_clp]->end_lat = trk[trk_end]->lat;
- clp[n_clp]->end_lon = trk[trk_end]->lon;
- }
- else
- {
- clp[n_clp]->begin_lat = 0x7fffffff;
- clp[n_clp]->begin_lon = 0x7fffffff;
- clp[n_clp]->end_lat = 0x7fffffff;
- clp[n_clp]->end_lon = 0x7fffffff;
- }
- clp[n_clp]->avg_heart_rate = 0; /* FIXME: Calculate */
- clp[n_clp]->max_heart_rate = 0; /* FIXME: Calculate */
- clp[n_clp]->intensity = 0;
- clp[n_clp]->avg_cadence = 0xff; /* FIXME: Calculate */
- n_crs++;
- n_clp++;
+ new_crs = n_crs;
+ for (i=0;i<n_trk;i++) {
+ if (!trk[i]->ishdr)
+ continue;
+
+ /* Find end of track */
+ for (trk_end=i; trk_end<n_trk-1; trk_end++)
+ if (trk[trk_end+1]->ishdr)
+ break;
+ if (trk_end==i)
+ trk_end=0; /* Empty track */
+
+ /* Create & append course */
+ crs = xrealloc(crs, (n_crs+1) * sizeof(GPS_PCourse));
+ crs[n_crs] = GPS_Course_New();
+ if (!crs[n_crs]) return MEMORY_ERROR;
+
+ crs[n_crs]->index = Unique_Course_Index(crs, n_crs);
+ strncpy(crs[n_crs]->course_name, trk[i]->trk_ident,
+ sizeof(crs[n_crs]->course_name)-1);
+
+ crs[n_crs]->track_index = Unique_Track_Index(crs, n_crs);
+
+ /* Create & append new lap */
+ clp = xrealloc(clp, (n_clp+1) * sizeof(GPS_PCourse_Lap));
+ clp[n_clp] = GPS_Course_Lap_New();
+ if (!clp[n_clp]) return MEMORY_ERROR;
+
+ clp[n_clp]->course_index = crs[n_crs]->index; /* Index of associated course */
+ clp[n_clp]->lap_index = 0; /* Lap index, unique per course */
+ Calculate_Course_Lap_Data(clp[n_clp], trk, i+1, trk_end);
+ n_crs++;
+ n_clp++;
}
/* Append new track points */
- ctk = realloc(ctk, (n_ctk+n) * sizeof(GPS_PTrack));
- if (!ctk) return MEMORY_ERROR;
-
- for (i=0;i<n;i++) {
- ctk[n_ctk] = GPS_Track_New();
- if (!ctk[n_ctk]) return MEMORY_ERROR;
- *ctk[n_ctk] = *trk[i];
-
- if (ctk[n_ctk]->ishdr)
- {
- /* Index of new track, must match the track index in associated course */
- memset(ctk[n_ctk]->trk_ident, 0, sizeof(ctk[n_ctk]->trk_ident));
- sprintf(ctk[n_ctk]->trk_ident, "%d", crs[trk_crs]->track_index);
- trk_crs++;
- }
- n_ctk++;
+ ctk = xrealloc(ctk, (n_ctk+n_trk) * sizeof(GPS_PTrack));
+
+ first_new_ctk = n_ctk;
+ for (i=0;i<n_trk;i++) {
+ ctk[n_ctk] = GPS_Track_New();
+ if (!ctk[n_ctk]) return MEMORY_ERROR;
+ *ctk[n_ctk] = *trk[i];
+
+ if (ctk[n_ctk]->ishdr)
+ {
+ /* Index of new track, must match the track index in associated course */
+ memset(ctk[n_ctk]->trk_ident, 0, sizeof(ctk[n_ctk]->trk_ident));
+ sprintf(ctk[n_ctk]->trk_ident, "%d", crs[new_crs]->track_index);
+ new_crs++;
+ }
+ n_ctk++;
+ }
+
+ /* Convert waypoints to course points by searching closest track point &
+ * append
+ */
+ cpt = xrealloc(cpt, (n_cpt+n_wpt) * sizeof(GPS_PCourse_Point));
+ for (i=0; i<n_wpt; i++)
+ {
+ double dist, min_dist = DBL_MAX;
+ int min_dist_idx = 0, trk_idx = 0, min_dist_trk_idx = 0;
+
+ /* Find closest track point */
+ for (j=first_new_ctk; j<first_new_ctk+n_trk; j++) {
+ if (ctk[j]->ishdr) {
+ trk_idx = strtoul(ctk[j]->trk_ident, NULL, 0);
+ continue;
+ }
+
+ dist = gcgeodist(wpt[i]->lat, wpt[i]->lon, ctk[j]->lat, ctk[j]->lon);
+ if (dist < min_dist) {
+ min_dist = dist;
+ min_dist_idx = j;
+ min_dist_trk_idx = trk_idx;
+ }
+ }
+
+ cpt[i+n_cpt] = GPS_Course_Point_New();
+ strncpy(cpt[i+n_cpt]->name, wpt[i]->cmnt,
+ sizeof(cpt[i+n_cpt]->name) - 1);
+ for (j=0; j<n_crs; j++)
+ if (crs[j]->track_index == min_dist_trk_idx)
+ {
+ cpt[i+n_cpt]->course_index = crs[j]->index;
+ break;
+ }
+ cpt[i+n_cpt]->track_point_time = ctk[min_dist_idx]->Time;
+ cpt[i+n_cpt]->point_type = 0;
}
+ n_cpt += n_wpt;
/* Remove course data that's no longer needed */
Course_Garbage_Collect(crs, &n_crs, clp, &n_clp, ctk, &n_ctk, cpt, &n_cpt);
int32 GPS_Command_Send_Course(const char *port, GPS_PCourse *crs, GPS_PCourse_Lap *clp,
GPS_PTrack *trk, GPS_PCourse_Point *cpt,
int32 n_crs, int32 n_clp, int32 n_trk, int32 n_cpt);
-int32 GPS_Command_Send_Track_As_Course(const char *port, GPS_PTrack *trk, int32 n);
+int32 GPS_Command_Send_Track_As_Course(const char *port, GPS_PTrack *trk, int32 n_trk,
+ GPS_PWay *wpt, int32 n_wpt);
int32 GPS_Command_Get_Workout(const char *port, void **lap, int (*cb)(int, struct GPS_SWay **));
int32 GPS_Command_Get_Fitness_User_Profile(const char *port, void **lap, int (*cb)(int, struct GPS_SWay **));